/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufpr.inf.escel.brain.model.po;

import br.ufpr.inf.escel.brain.util.PrimitivosUtils;
import java.util.ArrayList;

/**
 *
 * @author gustavo
 */
public class Metodos {

    private String[] metodos;

    public Metodos(String[] metodos) {
        this.metodos = new String[metodos.length];

        for (int i = 0; i < metodos.length; i++) {
            this.metodos[i] = metodos[i].trim();
        }
    }

    public Metodos() {
    }

    public static Metodos getInstance() {
        return new Metodos();
    }

    /**
     * tamanho do vetor de metodos
     * @return tamanho do vetor
     * @since 3.4
     */
    public int quantidade() {
        return (null != metodos) ? metodos.length : 0;
    }

    /**
     * Sorteia um metodo do vetor e cria uma instancia
     *
     * @return new Metodo() sorteado
     * @since 3.4
     */
    public Metodo sortearMetodo() {
        int indiceMetodo = (int) (Math.random() * quantidade());
        Metodo m = new Metodo(metodos[indiceMetodo], indiceMetodo);

        return m;
    }

    /**
     * Retorna uma instancia do metodo requisitado
     * @param indice do metodo
     * @return instancia do objeto
     * @since 3.4
     */
    public Metodo getMetodo(int indice) {
        return new Metodo(metodos[indice], indice);
    }

    /**
     * Recupera o ultimo metodo do vetor
     * @return
     */
    public Metodo getLastMetodo() {
        return new Metodo(metodos[quantidade() - 1], quantidade() - 1);
    }

    /**
     * Remove o metodo de acordo com o indice
     * @param indice do metodo
     * @since 3.4
     */
    public void removerMetodo(int indiceMetodo) {
        //converte pra list
        ArrayList list = PrimitivosUtils.arrayToList(metodos);
        //remove
        list.remove(indiceMetodo);
        //volta pra array
        String[] novosMetodos = PrimitivosUtils.listToArray(list);
        //altera a referencia
        this.metodos = novosMetodos;
    }

    /**
     * Adiciona um metodo no fim do vetor de metodos
     * @param metodo que vai ser adicionado
     * @since 3.4
     */
    public Metodo adicionarMetodo(String metodo) {
        if (!metodo.contains("(") && !metodo.contains(")")) {
            metodo = metodo + "()";
        }
        metodo = "$" + getVariavelReferencia() + "." + metodo.trim();

        String[] novosMetodos;

        if (this.metodos != null) {
            novosMetodos = copyMetodos(this.metodos);
        } else {
            novosMetodos = new String[1];
        }

        novosMetodos[novosMetodos.length - 1] = metodo;
        this.metodos = novosMetodos;

        return new Metodo(metodo);
    }

    /**
     * Adiciona um metodo no fim do vetor de metodos
     * @param metodo que vai ser adicionado
     * @since 4.1
     */
    public void adicionarMetodo(Metodo metodo) {
        String novosMetodos[] = copyMetodos(this.metodos);
        novosMetodos[novosMetodos.length - 1] = metodo.toString();
        this.metodos = novosMetodos;
    }

    /**
     * Copia um vetor de Strings, passando o vetor novo e antigo como parametros
     * @param antigosMetodos
     * @param novosMetodos
     * @return 4.1
     */
    private String[] copyMetodos(String[] antigosMetodos) {
        String novosMetodos[] = null;

        if (antigosMetodos != null) {
            novosMetodos = new String[antigosMetodos.length + 1];

            for (int i = 0; i < antigosMetodos.length; i++) {
                novosMetodos[i] = antigosMetodos[i];
            }

        } else {
            novosMetodos = new String[1];
        }

        return novosMetodos;
    }

    /**
     * Sobrescrita do toString(). Formata o vetor de
     * metodos como string para saida.
     * @return vetor de metodos como string
     * @since 3.4
     */
    @Override
    public String toString() {
        return (null != metodos) ? PrimitivosUtils.arrayToString(metodos, " : ") : "";
    }

    /**
     * Conta quantos parametros são necessários para
     * todas as chamadas de método
     * @return numero total de parametros
     * @since 3.9
     */
    public int totalParametro() {
        int total = 0;
        for (int i = 0; i < metodos.length; i++) {
            Metodo m = new Metodo(metodos[i]);
            total = total + m.quantidadeParametros();
        }
        return total;
    }

    /**
     * Pega a variavel que serve como referencia à chamada de metodo
     * ex: $x.swap(II) -> x
     * @return char at point 1
     */
    public String getVariavelReferencia() {
        return "x";
    }
}
